package com.example.service.impl;

import cn.novelweb.tool.http.Result;
import cn.novelweb.tool.upload.local.LocalUpload;
import cn.novelweb.tool.upload.local.pojo.UploadFileParam;
import com.example.Utils.NovelWebUtils;
import com.example.Utils.UuidUtils;
import com.example.constant.FileConstant;
import com.example.entity.FilesEntity;
import com.example.enums.ErrorCode;
import com.example.mapper.FilesMapper;
import com.example.model.dto.AddFileInfo;
import com.example.model.dto.GetFileInfo;
import com.example.model.response.ServiceResult;
import com.example.model.response.ServiceResultEntity;
import com.example.service.FilesService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.util.List;

@Slf4j
@Service
public class FilesServiceImpl implements FilesService {

    // ：后面表示默认值，当配置文件中没有，则使用默认值
    @Value("${file.save-path:/fileUpload/files}")
    private String savePath;

    @Value("${file.conf-path:/fileUpload/files/conf}")
    private String confPath;

    @Autowired
    private FilesMapper filesMapper;

    // 分页获取文件信息列表
    @Override
    public ServiceResult<List<GetFileInfo>> getFileInfoList(Integer pageNo, Integer pageSize) {
        PageHelper.startPage(pageNo, pageSize);
        List<GetFileInfo> getFileInfoList = filesMapper.selectFileList();
        if (getFileInfoList.isEmpty()) {
            return ServiceResultEntity.newFailResult(ErrorCode.DATABASE_ERROR, "数据出错！");
        }
        PageInfo<GetFileInfo> pageInfo = new PageInfo<>(getFileInfoList);
        // 把总数据数作为额外信息带出去
        return ServiceResultEntity.newSuccessResult(pageInfo.getList(), "查询成功！", pageInfo.getTotal());
    }


    // 根据id获取文件信息
    @Override
    public ServiceResult<FilesEntity> getFileInfoById(String id) {
        FilesEntity filesEntity = filesMapper.selectById(id);
        if (filesEntity == null) {
            return ServiceResultEntity.newFailResult(ErrorCode.DATA_NOT_FOUND, "数据不存在！");
        }
        return ServiceResultEntity.newSuccessResult(filesEntity, "查询成功！");
    }


    // 获取文件输入流
    @Override
    public InputStream getFileInputStream(String id) {
        try {
            FilesEntity filesEntity = filesMapper.selectById(id);
            return new FileInputStream(savePath + File.separator + filesEntity.getFilePath());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            log.error("获取文件输入流出错！", e);
            return null;
        }
    }


    // 小文件上传
    @Override
    public ServiceResult<String> uploadFiles(MultipartFile file) {
        try {
            // 1.原始文件名
            String originalFileName = file.getOriginalFilename();
            if (originalFileName == null || originalFileName.trim().isEmpty()) {
                return ServiceResultEntity.newFailResult(ErrorCode.FILE_ERROR, "文件名不能为空！");
            }

            // 2.大文件判定
            if (file.getSize() > FileConstant.MAX_SIZE) {
                return ServiceResultEntity.newFailResult(ErrorCode.FILE_ERROR, "文件过大，请使用大文件传输！");
            }

            // 3.解析后缀
            // String suffixName = originalFilename.contains(".") ? originalFilename.substring(originalFilename.lastIndexOf(".")) : null;
            // 需要优化：
            // 当文件名以 "." 开头时，是隐藏文件
            // 当文件名以 "." 结尾，比如 abc. 也会得到 . 不是有效后缀
            String suffix = "";
            int dotIndex = originalFileName.lastIndexOf(".");
            if (dotIndex <= 0 || dotIndex == originalFileName.length() - 1) {
                return ServiceResultEntity.newFailResult(ErrorCode.FILE_ERROR, "文件缺少后缀！");
            } else {
                // 取后缀名，不包含. 并且转为小写
                suffix = originalFileName.substring(dotIndex + 1).toLowerCase();
            }

            // 4.还可以判断文件类型白名单（可选）
            if (!FileConstant.FILE_TYPES.contains(suffix)) {
                return ServiceResultEntity.newFailResult(ErrorCode.FILE_ERROR, "不支持该文件类型！");
            }

            // 5.生成新文件名：uuid + 后缀
            String newFileName = UuidUtils.getUuid() + "." + suffix;

            // 6.确保目录存在：可以并入一步
//            File dir = new File(savePath);
//            if (!dir.exists()) {
//                dir.mkdirs();
//            }
//
//            // 写入文件
//            File path = new File(dir, newFileName);
//            file.transferTo(path);

            File dir = new File(savePath, newFileName);
            if (!dir.getParentFile().exists()) {
                dir.getParentFile().mkdirs();
            }
            file.transferTo(dir);

            // 7.写入数据库
            FilesEntity filesEntity = new FilesEntity();
            filesEntity.setFileName(originalFileName)
                    .setFilePath(newFileName)
                    .setSuffix(suffix);
            filesMapper.insert(filesEntity);
            // 把id传出去
            return ServiceResultEntity.newSuccessResult(filesEntity.getId(), "文件上传成功！");
        } catch (IOException e) {
            log.error("上传协议文件出错！", e);
        }
        return ServiceResultEntity.newFailResult(ErrorCode.FILE_UPLOAD_ERROR, "文件上传失败！");
    }


    // 检查文件md5
    @Override
    public ServiceResult<Object> checkFileMd5(String md5, String fileName) {
        try {
            Result<?> result = LocalUpload.checkFileMd5(md5, fileName, confPath, savePath);
            return NovelWebUtils.forReturn(result);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ServiceResultEntity.newFailResult(ErrorCode.FILE_UPLOAD_ERROR, "上传失败！");
        }
    }


    // 断点续传：大文件上传
    @Override
    public ServiceResult<Object> breakpointResumeUpload(UploadFileParam param, HttpServletRequest request) {
        try {
            Result<?> result = LocalUpload
                    .fragmentFileUploader(param, confPath, savePath, FileConstant.CHUNK_SIZE, request);
            return NovelWebUtils.forReturn(result);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ServiceResultEntity.newFailResult(ErrorCode.FILE_UPLOAD_ERROR, "上传失败！");
        }
    }


    // 添加文件
    @Override
    public ServiceResult<String> addFile(AddFileInfo addFileInfo) {
        FilesEntity filesEntity = new FilesEntity();
        BeanUtils.copyProperties(addFileInfo, filesEntity);
        if (filesMapper.fileIsExist(addFileInfo.getFileName())) {
            return ServiceResultEntity.newFailResult(ErrorCode.DATA_EXIST, "数据已存在，添加失败！");
        }
        int insert = filesMapper.insert(filesEntity.setFilePath(addFileInfo.getFileName()));
        if (insert != 0) {
            return ServiceResultEntity.newSuccessResult(null, "添加成功！");
        } else {
            return ServiceResultEntity.newFailResult(ErrorCode.INTERNAL_CALL_ERROR, "添加失败！");
        }
    }
}

